package jmine.tec.scheduling.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import jmine.tec.persist.annotation.Alias;
import jmine.tec.persist.annotation.Constraint;
import jmine.tec.persist.annotation.Index;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.Type;
import org.hibernate.validator.NotNull;

import bancosys.tec.component.Documentation;
import bancosys.tec.persist.bussobj.PersistableBusinessObject;
import bancosys.tec.rtm.exception.ExceptionRecord;
import bancosys.tec.utils.date.Timestamp;

/**
 * @author lundberg
 */
@Entity
@Alias("SCTKEX")
@Table(name = "SCHEDULED_TASK_EXECUTION")
@Documentation("EXECUCAO DE UMA TAREFA AGENDADA")
@SequenceGenerator(name = "SEQ_SCTKEX", sequenceName = "SEQ_SCTKEX")
public class ScheduledTaskExecution extends PersistableBusinessObject {

    private Long id;

    private ScheduledTask task;

    private ScheduledTaskExecutionStatus status;

    private Timestamp start;

    private Timestamp end;

    private String trace;

    private ExceptionRecord exception;

    /**
     * Constructor
     */
    public ScheduledTaskExecution() {
        // OK
    }

    /**
     * Constructor
     * 
     * @param task task
     * @param status status
     * @param start start
     * @param end end
     * @param trace trace
     * @param exception exception
     */
    private ScheduledTaskExecution(ScheduledTask task, ScheduledTaskExecutionStatus status, Timestamp start, Timestamp end, String trace,
            ExceptionRecord exception) {
        super();
        this.task = task;
        this.status = status;
        this.start = start;
        this.end = end;
        this.trace = trace;
        this.exception = exception;
    }

    /**
     * Creates an execution log corresponding to a successful execution
     * 
     * @param task task
     * @param start start
     * @param end end
     * @param trace trace
     * @return ScheduledTaskExecution
     */
    public static ScheduledTaskExecution executed(ScheduledTask task, Timestamp start, Timestamp end, String trace) {
        return new ScheduledTaskExecution(task, ScheduledTaskExecutionStatus.EXECUTED, start, end, trace, null);
    }

    /**
     * Creates an execution log corresponding to skiped execution
     * 
     * @param task task
     * @param start start
     * @param end end
     * @param trace trace
     * @return ScheduledTaskExecution
     */
    public static ScheduledTaskExecution notExecuted(ScheduledTask task, Timestamp start, Timestamp end, String trace) {
        return new ScheduledTaskExecution(task, ScheduledTaskExecutionStatus.NOT_EXECUTED, start, end, trace, null);
    }

    /**
     * Creates an execution log corresponding to failed execution
     * 
     * @param task task
     * @param start start
     * @param end end
     * @param trace trace
     * @param exceptionRecord {@link ExceptionRecord}
     * @return ScheduledTaskExecution
     */
    public static ScheduledTaskExecution fail(ScheduledTask task, Timestamp start, Timestamp end, String trace,
            ExceptionRecord exceptionRecord) {
        return new ScheduledTaskExecution(task, ScheduledTaskExecutionStatus.FAILED, start, end, trace, exceptionRecord);
    }

    /**
     * @return the id
     */
    @Id
    @GeneratedValue(generator = "SEQ_SCTKEX")
    @Documentation("CODIGO DA EXECUCAO DA TAREFA AGENDADA")
    @Column(name = "COD_SCHEDULED_TASK_EXECUTION", nullable = false)
    public Long getId() {
        return this.id;
    }

    /**
     * @return the task
     */
    @NotNull
    @Index(suffix = "JT_0")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "COD_SCHEDULED_TASK", nullable = false)
    @Documentation("CODIGO DA TAREFA AGENDADA EXECUTADA")
    public ScheduledTask getTask() {
        return this.task;
    }

    /**
     * @return the status
     */
    @NotNull
    @Constraint(suffix = "JT_0")
    @Column(name = "ST", nullable = false)
    @Documentation("STATUS DA EXECUCAO DA TAREFA")
    public ScheduledTaskExecutionStatus getStatus() {
        return this.status;
    }

    /**
     * @return the start
     */
    @NotNull
    @Index(suffix = "JT_1")
    @Type(type = "bancosys.tec.persist.hibernate.type.TimestampType")
    @Column(name = "TS_START", nullable = false)
    @Documentation("HORARIO DE INICIO DA EXECUCAO DA TAREFA")
    public Timestamp getStart() {
        return this.start;
    }

    /**
     * @return the end
     */
    @NotNull
    @Type(type = "bancosys.tec.persist.hibernate.type.TimestampType")
    @Column(name = "TS_END", nullable = false)
    @Documentation("HORARIO DE FIM DA EXECUCAO DA TAREFA")
    public Timestamp getEnd() {
        return this.end;
    }

    /**
     * @return the trace
     */
    @NotNull
    @Lob
    @Type(type = "org.hibernate.type.StringClobType")
    @Column(name = "TRACE", nullable = false)
    @Documentation("LOG DA EXECUCAO DA TAREFA")
    public String getTrace() {
        return this.trace;
    }

    /**
     * @return the exception
     */
    @Index(suffix = "JT_2")
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = bancosys.tec.rtm.impl.exception.domain.ExceptionRecord.class)
    @JoinColumn(name = "COD_EXCEPTION")
    @Documentation("CODIGO DA EXCECAO OCORRIDA DURANTE A EXECUCAO DA TAREFA, CASO APLICAVEL")
    public ExceptionRecord getException() {
        return this.exception;
    }

    /**
     * @param id the id to set
     */
    public void setId(Long id) {
        this.id = id;
    }

    /**
     * @param task the task to set
     */
    public void setTask(ScheduledTask task) {
        this.task = task;
    }

    /**
     * @param status the status to set
     */
    public void setStatus(ScheduledTaskExecutionStatus status) {
        this.status = status;
    }

    /**
     * @param start the start to set
     */
    public void setStart(Timestamp start) {
        this.start = start;
    }

    /**
     * @param end the end to set
     */
    public void setEnd(Timestamp end) {
        this.end = end;
    }

    /**
     * @param trace the trace to set
     */
    public void setTrace(String trace) {
        this.trace = trace;
    }

    /**
     * @param exception the exception to set
     */
    public void setException(ExceptionRecord exception) {
        this.exception = exception;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}
